Conditions | 16 |
Paths | 8910 |
Total Lines | 69 |
Lines | 0 |
Ratio | 0 % |
Changes | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like Aes.Ctr.encrypt often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
1 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
||
38 | Aes.Ctr.encrypt = function(plaintext, password, nBits) { |
||
39 | var blockSize = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES |
||
40 | if (!(nBits==128 || nBits==192 || nBits==256)) throw new Error('Key size is not 128 / 192 / 256'); |
||
41 | plaintext = String(plaintext).utf8Encode(); |
||
42 | password = String(password).utf8Encode(); |
||
43 | |||
44 | // use AES itself to encrypt password to get cipher key (using plain password as source for key |
||
45 | // expansion) - gives us well encrypted key (though hashed key might be preferred for prod'n use) |
||
46 | var nBytes = nBits/8; // no bytes in key (16/24/32) |
||
47 | var pwBytes = new Array(nBytes); |
||
48 | for (var i=0; i<nBytes; i++) { // use 1st 16/24/32 chars of password for key |
||
49 | pwBytes[i] = i<password.length ? password.charCodeAt(i) : 0; |
||
50 | } |
||
51 | var key = Aes.cipher(pwBytes, Aes.keyExpansion(pwBytes)); // gives us 16-byte key |
||
52 | key = key.concat(key.slice(0, nBytes-16)); // expand key to 16/24/32 bytes long |
||
53 | |||
54 | // initialise 1st 8 bytes of counter block with nonce (NIST SP800-38A §B.2): [0-1] = millisec, |
||
55 | // [2-3] = random, [4-7] = seconds, together giving full sub-millisec uniqueness up to Feb 2106 |
||
56 | var counterBlock = new Array(blockSize); |
||
57 | |||
58 | var nonce = (new Date()).getTime(); // timestamp: milliseconds since 1-Jan-1970 |
||
59 | var nonceMs = nonce%1000; |
||
60 | var nonceSec = Math.floor(nonce/1000); |
||
61 | var nonceRnd = Math.floor(Math.random()*0xffff); |
||
62 | // for debugging: nonce = nonceMs = nonceSec = nonceRnd = 0; |
||
63 | |||
64 | for (var i=0; i<2; i++) counterBlock[i] = (nonceMs >>> i*8) & 0xff; |
||
65 | for (var i=0; i<2; i++) counterBlock[i+2] = (nonceRnd >>> i*8) & 0xff; |
||
66 | for (var i=0; i<4; i++) counterBlock[i+4] = (nonceSec >>> i*8) & 0xff; |
||
67 | |||
68 | // and convert it to a string to go on the front of the ciphertext |
||
69 | var ctrTxt = ''; |
||
70 | for (var i=0; i<8; i++) ctrTxt += String.fromCharCode(counterBlock[i]); |
||
71 | |||
72 | // generate key schedule - an expansion of the key into distinct Key Rounds for each round |
||
73 | var keySchedule = Aes.keyExpansion(key); |
||
74 | |||
75 | var blockCount = Math.ceil(plaintext.length/blockSize); |
||
76 | var ciphertext = ''; |
||
77 | |||
78 | for (var b=0; b<blockCount; b++) { |
||
79 | // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes) |
||
80 | // done in two stages for 32-bit ops: using two words allows us to go past 2^32 blocks (68GB) |
||
81 | for (var c=0; c<4; c++) counterBlock[15-c] = (b >>> c*8) & 0xff; |
||
82 | for (var c=0; c<4; c++) counterBlock[15-c-4] = (b/0x100000000 >>> c*8); |
||
83 | |||
84 | var cipherCntr = Aes.cipher(counterBlock, keySchedule); // -- encrypt counter block -- |
||
85 | |||
86 | // block size is reduced on final block |
||
87 | var blockLength = b<blockCount-1 ? blockSize : (plaintext.length-1)%blockSize+1; |
||
88 | var cipherChar = new Array(blockLength); |
||
89 | |||
90 | for (var i=0; i<blockLength; i++) { |
||
91 | // -- xor plaintext with ciphered counter char-by-char -- |
||
92 | cipherChar[i] = cipherCntr[i] ^ plaintext.charCodeAt(b*blockSize+i); |
||
93 | cipherChar[i] = String.fromCharCode(cipherChar[i]); |
||
94 | } |
||
95 | ciphertext += cipherChar.join(''); |
||
96 | |||
97 | // if within web worker, announce progress every 1000 blocks (roughly every 50ms) |
||
98 | if (typeof WorkerGlobalScope != 'undefined' && self instanceof WorkerGlobalScope) { |
||
99 | if (b%1000 == 0) self.postMessage({ progress: b/blockCount }); |
||
100 | } |
||
101 | } |
||
102 | |||
103 | ciphertext = (ctrTxt+ciphertext).base64Encode(); |
||
104 | |||
105 | return ciphertext; |
||
106 | }; |
||
107 | |||
226 |